﻿

using IotContract.Dtos.Clients;
using IotContract.Dtos.Servers;
using IotContract.Enums;
using IotContract.Interfaces.Fmt;
using IotContract.Interfaces;
using IotContract.Interfaces.Process;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XT.Common.Services;
using IotContract.Dtos.Servers.Process;
using IotContract.Dtos.Servers.Pushs;
using XT.Common.Extensions;
using System.Collections.Concurrent;
using F29ServerProcess.Interfaces;
using F29ServerProcess.Models;
using Mapster;
using IotContract.Dtos.Clients.Equips;
using IotContract.Extensions;
using XT.Common.Enums;
using IotContract.Models.Jobs.F29;

namespace _29ServerProcess.DataProcess;
/// <summary>
/// 物流线数据处理程序
/// </summary>
public class CvDataProcess : IServerProcessHandle
{
    private readonly IServerMainManager _mainProcess;
    private readonly IProcessDataService _processDataService;
    private readonly IProcessJobService _processJobService;
    private readonly ILogService _logService;
    

    public CvDataProcess(IServerMainManager serverMainManager, IProcessDataService processDataService,IProcessJobService processJobService, ILogService logService)
    {
        _mainProcess = serverMainManager;
        _processDataService = processDataService;
        _processJobService = processJobService;
        _logService = logService;
    }
    public string ProcessName { get; set; } = F29ServerConst.ProcessName;
    public IotEquipType ProcessType { get; set; } = IotEquipType.CV;

    public event EventHandler<IotEquipWarnDto> WarnEvent;

   

    /// <summary>
    /// 解析数据
    /// </summary>
    /// <returns></returns>
    public async Task<bool> ParsingData()
    {
        try
        {
            // 获取数据
            var equips = await _mainProcess.GetEquips<PushSiemensS7Dto>(new IotContract.Models.Clients.ClientRequestCommand
            {
                RequestType = IotEquipType.CV.ToString(),
                ProtobufType = IotProtobufType.SIEMENS_S7.ToString()
            });
            // 获取扫码枪
            var bcrs = await _mainProcess.GetEquips<PushBcrDto>(new IotContract.Models.Clients.ClientRequestCommand
            {
                RequestType = IotEquipType.BCR.ToString(),
                ProtobufType = IotProtobufType.HBC_BCR.ToString()
            });

            if(equips.Count==0)
            {
                return false;
            }
            
            List<PushEquipTag> tags = new List<PushEquipTag>();
            foreach (var equip in equips)
            {
                tags.AddRange(equip.Tags);
            }

            // tags根据TagNum分组,TagNum=UnitNum，TagNum 也就是站台号
            var tagDic = tags.ToLookup(x => x.TagNum).ToDictionary(x => x.Key, y => y.ToList());

            var bcrDic = bcrs.ToLookup(x => x.UnitNum).ToDictionary(x => x.Key, y => y.ToList());

            var cvUnitDic = _processDataService.CvUnitTags;

            Parallel.ForEach(tagDic.Keys, x =>
            {
                var tagNum = x.To<int>();
                // 设备号
                var tags = tagDic[x];
                
                F29CvUnitDto unitTag = null;
                if (cvUnitDic.ContainsKey(tagNum))
                {
                    unitTag = cvUnitDic[tagNum];
                }
                else
                {
                    unitTag = new F29CvUnitDto();
                    unitTag.TagNum = tagNum;
                   
                  
                    cvUnitDic.TryAdd(tagNum, unitTag);
                }
                
                var equip = equips.FirstOrDefault(x => x.Id == tags.FirstOrDefault()?.EquipInfoId);
                unitTag.EquipNum = equip.Num;
                unitTag.EquipId = equip.Id;
                unitTag.Connection = equip.Connection;
                unitTag.ProtobufType = equip.ProtobufType;

                // 赋值扫码枪           
                if (bcrDic.ContainsKey(x))
                {                 
                    unitTag.Bcrs = bcrDic[x];
                }
                else
                {
                    unitTag.Bcrs = new List<PushBcrDto>();
                }

                SetUnitTag(unitTag, tags);
            });


        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        return true;


    }

    /// <summary>
    /// 设置unit的值
    /// </summary>
    /// <param name="unitTag"></param>
    private void SetUnitTag(F29CvUnitDto unitTag, List<PushEquipTag> tags)
    {
        unitTag.Tags = tags;
        Parallel.ForEach(tags, x =>
        {
            int.TryParse(x.Value, out int result);
            switch (x.TagProperty)
            {
                case "ERROR":
                    {
                        unitTag.Error = result;
                        break;
                    }
                case "MODE":
                    {
                        unitTag.Mode = result;
                        break;
                    }
                case "W_TIME":
                    {
                        unitTag.StackOnTime = result;
                        break;
                    }

                case "ALLOW_ENTER":
                    {
                        unitTag.AllowEnter = result;
                        break;
                    }
                case "ALLOW_OUT":
                    {
                        unitTag.AllowOut = result;

                        break;
                    }             
                case "STACK_OVER":
                    {
                        unitTag.StackOver = result;
                        break;
                    }
                case "BCR_READY":
                    {
                        unitTag.BcrReady = result;
                        break;
                    }
                case "TASK":
                    {
                        unitTag.TaskNumber = result;                       
                        break;
                    }
                case "TRAY_EXIST2":
                    {
                        unitTag.IsExistTray2 = result == 1;
                        break;
                    }             
                case "TRAY_EXIST1":
                    {
                        if (result == 1 && !unitTag.IsExistTray1)
                        {
                            unitTag.TrayInTime = DateTime.Now;
                        }
                        if (result == 0)
                        {
                            unitTag.TrayInTime = null;
                            unitTag.TrayOnTime = 0;
                        }
                        if (unitTag.TrayInTime != null)
                        {
                            unitTag.TrayOnTime = Math.Round(DateTime.Now.Subtract(unitTag.TrayInTime.Value).TotalMinutes, 0);
                        }
                        unitTag.IsExistTray1 = result == 1;
                        break;
                    }
                case "DEST":
                    {
                        unitTag.Dest = result;
                        break;
                    }
                case "W_TRAY_TYPE":
                    {
                        unitTag.TrayType = result;
                        break;
                    }
                case "W_DONE":
                    {
                        unitTag.WriteDone = result;
                        break;
                    }



            }

        });
      
    }

    public async Task<bool> ProcessData()
    {
        Parallel.ForEach(_processDataService.CvUnitTags.Values, async x =>
        {
            // 叠盘逻辑
            if(x.StackOver==1 )
            {
                if (x.StackOutTime == null)
                {
                    x.StackOutTime = DateTime.Now;
                    HandleStack(x);
                }
                else
                {
                    // 15s以后还是没有复位，重新进行调用
                    if(DateTime.Now.Subtract(x.StackOutTime.Value).TotalSeconds >= 15)
                    {
                        x.StackOutTime = null;
                    }
                }
            }
            else
            {
                x.StackOutTime = null;
            }

           

            // 扫码逻辑
            if (x.Bcrs.Count == 0)
            {
                _processDataService.SetTrayByTask(x);
                return;
            }

            if (x.Bcrs.First().Connection == false) return;

            // 手动模式
            if (x.Mode == 0) return;
            
            HandleBcrToCommit(x);

        });

        return true;
    }
    /// <summary>
    /// 处理叠盘逻辑
    /// </summary>
    /// <param name="unit"></param>
    private void HandleStack(F29CvUnitDto unit)
    {
        Task.Run(async() =>
        {
            await _logService.LogContent($"{unit.TagNum} 叠盘完成，收到信号 {unit.StackOutTime}", LogEnum.Info, unit.TagNum.ToString());
            var result= await _processDataService.CommitStackOver(unit.TagNum);
            if (result.Success)
            {
                await _logService.LogContent($"{unit.TagNum} 叠盘调用完成", LogEnum.Info, unit.TagNum.ToString());

               await _processDataService.WriteCvStatus(unit.TagNum, 1);
            }
            else
            {
                await _logService.LogContent($"{unit.TagNum} 叠盘调用失败", LogEnum.Error, unit.TagNum.ToString());
            }
        });
    }

    /// <summary>
    /// 处理扫码逻辑
    /// </summary>
    /// <param name="unit"></param>
    private async void HandleBcrToCommit(F29CvUnitDto unit)
    {
        if (!unit.IsExistTray1)
        {
           _processDataService.ClearTag(unit);
            return;
        }
        // 携带错误信息，不提交
        if (unit.Message.IsNotNullOrEmpty() || unit.Error > 0) return;

        // 正在提交中
        if (unit.Commiting == true) return;

        // 已经进行过提交，拥有提交后的任务
        if (unit.CommitReturnTask > 0)
        {
            // 如果是入库站台
            if (_processDataService.GetUnitTagType(unit.TagNum) > 0)
            {
                // 放下的位置
                if (unit.BcrReady == 1 && unit.AllowEnter==0)
                {
                    await Task.Delay(1000);
                    _processDataService.ClearTag(unit);
                }
            }

            return;
        }
        

       

        if (unit.BcrReady == 0) return;
        // 允许取货
        if (unit.AllowEnter == 1) return;

        bool needReadBcr = false;

        if(unit.BcrReadTime==null || DateTime.Now.Subtract(unit.BcrReadTime.Value).TotalSeconds >= 5)
        {
           
            
             needReadBcr = await HandleReadBcrs(unit);
            
          
        }
      
        if (needReadBcr)
        {
            unit.BcrReadTime = DateTime.Now;
        }
        else
        {
            // 不用再扫码，开始读取并提交
            await HandleCommitTray(unit);
        }
    }

    
    /// <summary>
    /// 控制扫码枪扫码
    /// </summary>
    /// <param name="unit"></param>
    private async Task<bool> HandleReadBcrs(F29CvUnitDto unit)
    {
        // 发送读取扫码的个数
        int callCount = 0;
        // 总光电个数
        int readMaxBcr = 0;

        if (unit.BcrReadID.IsNullOrEmpty())
        {
            unit.BcrReadID=Guid.NewGuid().ToString();
        }

        if (unit.IsExistTray1)
        {
            readMaxBcr = 1;
            var bcr = unit.Bcrs.FirstOrDefault(x => x.OrderNum == 1);
            if (bcr != null)
            {
                if (bcr.ReadingStep != BcrProcessStepType.Read_Request || bcr.ReadingStep != BcrProcessStepType.Send_ReadPacket || bcr.ReadingStep == BcrProcessStepType.Read_RetryStop)
                {
                    if (bcr.WriteId==unit.BcrReadID)
                    {
                        if (!bcr.IsReadOK || bcr.Value == unit.Tray1Old)
                        {                          
                            await _processDataService.WriteBcr(unit.BcrReadID, bcr.Id);
                            callCount++;
                        }
                    }
                    else
                    {
                        await _processDataService.WriteBcr(unit.BcrReadID, bcr.Id);
                        callCount++;
                    }

                }
            }
        }
        if (unit.IsExistTray2)
        {
            readMaxBcr = 2;
            var bcr = unit.Bcrs.FirstOrDefault(x => x.OrderNum == 2);
            if (bcr != null)
            {
                if (bcr.ReadingStep != BcrProcessStepType.Read_Request || bcr.ReadingStep != BcrProcessStepType.Send_ReadPacket || bcr.ReadingStep == BcrProcessStepType.Read_RetryStop)
                {
                    if (bcr.WriteId == unit.BcrReadID)
                    {
                        if (!bcr.IsReadOK || bcr.Value == unit.Tray1Old)
                        {
                            await _processDataService.WriteBcr(unit.BcrReadID, bcr.Id);
                            callCount++;
                        }
                    }
                    else
                    {
                        await _processDataService.WriteBcr(unit.BcrReadID, bcr.Id);
                        callCount++;
                    }

                }
            }
        }

        unit.MaxReadBcr = readMaxBcr;

        return callCount > 0;
    }
    /// <summary>
    /// 提交扫码
    /// </summary>
    /// <param name="unit"></param>
    /// <returns></returns>
    private async Task HandleCommitTray(F29CvUnitDto unit)
    {
        unit.ReadOkBcr = 0;
        unit.Trays.Clear();
        if (unit.IsExistTray1)
        {
            var bcr = unit.Bcrs.FirstOrDefault(x => x.OrderNum == 1);
            if(bcr != null && bcr.WriteId==unit.BcrReadID && bcr.ReadingStep==BcrProcessStepType.Read_OK && bcr.Value.IsNotNullOrEmpty())
            {
                unit.ReadOkBcr++;
                unit.Tray1 = bcr.Value;
                if (bcr.IsReadOK && unit.Tray1 != unit.Tray1Old)
                {
                    unit.Trays.Add(bcr.Value);
                }
            }
        }
        if (unit.IsExistTray2)
        {
            var bcr = unit.Bcrs.FirstOrDefault(x => x.OrderNum == 2);
            if (bcr != null && bcr.WriteId == unit.BcrReadID && bcr.ReadingStep == BcrProcessStepType.Read_OK && bcr.Value.IsNotNullOrEmpty())
            {
                unit.ReadOkBcr++;
                unit.Tray1 = bcr.Value;
                if (bcr.IsReadOK && unit.Tray1 != unit.Tray1Old)
                {
                    unit.Trays.Add(bcr.Value);
                }
            }
        }

        if(unit.MaxReadBcr==unit.Trays.Count && unit.ReadOkBcr>0 && unit.ReadOkBcr==unit.MaxReadBcr && unit.TaskNumber > 0)
        {
            if (unit.Commiting) return ;
            unit.Commiting = true;
            unit.CommitTask = unit.TaskNumber;
            int callMethod = 0;
            int type= _processDataService.GetUnitTagType(unit.TagNum);

            // 双叉 2叉在前  1叉在后，1叉可去双站台
            // 非入库站台提交
            if (type==0)
            {
                callMethod = 0;
            }
            // 单库位提交，获取堆垛机任务
            else if (type == 1)
            {
              
                callMethod = 1;
               
            }
            // 双叉2叉站台，找到1叉托盘，一起提交获取堆垛机任务
            else if (type == 3)
            {
               var firstTag=_processDataService.GetEnterOtherTag(unit.TagNum);
                if (firstTag == null || firstTag.IsExistTray1==false)
                {
                    callMethod = 1;
                }
                else if(firstTag.Commiting && firstTag.Tray1.IsNotNullOrEmpty())
                {
                    callMethod = 2;
                    
                }
                else
                {
                    unit.Commiting = false;
                    return;
                }
            }
            // 双叉1叉站台，变成提交状态
            else if (type == 2)
            {
               var twoTag= _processDataService.GetEnterOtherTag(unit.TagNum);
                // 前站台报错直接单叉
                if(twoTag!=null || twoTag.Error>0 || twoTag.Mode==0)
                {
                    callMethod = 1;
                }
                else
                {
                 
                    return;
                }
            }

           
            Task.Run(async () =>
            {
                if (!unit.Commiting)
                {
                    return;
                }
                if (callMethod == 0)
                {
                    var result = await _processDataService.CommitTrays(unit);
                    // 存在异常
                    if (result.Success)
                    {
                        if (await _processDataService.WriteCv(result.Result))
                        {
                            unit.CommitReturnTask = result.Result.TaskNum;
                            _processDataService.SetTrayByTask(unit);
                            // 释放扫码
                            unit.BcrReadID = Guid.NewGuid().ToString();
                            unit.Tray1Old = unit.Tray1;
                            unit.Tray2Old = unit.Tray2;
                        }
                    }
                    else
                    {
                        unit.Message = result.Message;

                    }
                }
                // 单叉入库
                else if (callMethod == 1)
                {
                    var enterTask = await _processDataService.CommitEnterTrays(null, unit);

                    if (enterTask.Success)
                    {
                        await _processDataService.WriteCvStatus(unit.TagNum, 1);
                        // 添加任务
                        _processJobService.AddJob(enterTask.Result, ProcessProviderType.EnterJob);
                        unit.CommitReturnTask = enterTask.Result.FromTagNumber;
                        unit.BcrReadID = Guid.NewGuid().ToString();
                        unit.Tray1Old = unit.Tray1;
                        unit.Tray2Old = unit.Tray2;
                    }
                    else
                    {
                        unit.Message = enterTask.Message;
                    }
                }
                // 双叉入库
                else if (callMethod == 2)
                {
                    var unitTag1 = _processDataService.GetEnterOtherTag(unit.TagNum);
                    var doubleTask = await _processDataService.CommitEnterTrays(unit,unitTag1);
                    if (doubleTask.Success)
                    {
                        await _processDataService.WriteCvStatus(unitTag1.TagNum, 1);
                     
                        await _processDataService.WriteCvStatus(unit.TagNum, 1);
                        _processJobService.AddJob(doubleTask.Result, ProcessProviderType.EnterJob);
                        unit.CommitReturnTask = doubleTask.Result.FromTagNumber;
                        unit.BcrReadID = Guid.NewGuid().ToString();
                        unit.Tray1Old = unit.Tray1;
                        unit.Tray2Old = unit.Tray2;
                    }
                    else
                    {
                        unit.Message = doubleTask.Message;
                    }
                    unitTag1.Commiting = false;

                }
            }).ContinueWith(t =>
            {   
               
                unit.Commiting = false;
            });
        }
         
    }

    public async Task<bool> ProcessOrder()
    {
        return true;
    }

    public async Task<bool> ProcessWarn()
    {
        return true;
    }

    public bool Stop()
    {
        _processDataService.CvUnitTags.Clear();
        return true;
    }
}
